home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / cfengine-1.5.3 / src / image.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-09-14  |  32.9 KB  |  1,321 lines

  1. /* 
  2.  
  3.         Copyright (C) 1995
  4.         Free Software Foundation, Inc.
  5.  
  6.    This file is part of GNU cfengine - written and maintained 
  7.    by Mark Burgess, Dept of Computing and Engineering, Oslo College,
  8.    Dept. of Theoretical physics, University of Oslo
  9.  
  10.    This program is free software; you can redistribute it and/or modify it
  11.    under the terms of the GNU General Public License as published by the
  12.    Free Software Foundation; either version 2, or (at your option) any
  13.    later version.
  14.  
  15.    This program is distributed in the hope that it will be useful,
  16.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.    GNU General Public License for more details.
  19.  
  20.   You should have received a copy of the GNU General Public License
  21.   along with this program; if not, write to the Free Software
  22.   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
  23.  
  24. */
  25.  
  26.  
  27. /*******************************************************************/
  28. /*                                                                 */
  29. /* File Image copying                                              */
  30. /*                                                                 */
  31. /*******************************************************************/
  32.  
  33. #define INET 1
  34.  
  35. #include "cf.defs.h"
  36. #include "cf.extern.h"
  37.  
  38. /*********************************************************************/
  39. /* Level 1                                                           */
  40. /*********************************************************************/
  41.  
  42. RecursiveImage(ip,from,to,maxrecurse)
  43.  
  44. struct Image *ip;
  45. char *from, *to;
  46. int maxrecurse;
  47.  
  48. { struct stat statbuf, deststatbuf;
  49.   char newfrom[bufsize];
  50.   char newto[bufsize];
  51.   int save_uid, save_gid;
  52.   struct Item *namecache = NULL;
  53.   struct cfdirent *dirp;
  54.   CFDIR *dirh;
  55.  
  56. if (maxrecurse == 0)  /* reached depth limit */
  57.    {
  58.    Debug2("MAXRECURSE ran out, quitting at level %s with endlist = %d\n",from,ip->next);
  59.    return;
  60.    }
  61.  
  62. Debug2("RecursiveImage(%s,lev=%d,next=%d)\n",from,maxrecurse,ip->next);
  63.  
  64. if (IgnoreFile(from,"",ip->ignores))
  65.    {
  66.    Verbose("Ignoring directory %s\n",from);
  67.    return;
  68.    }
  69.  
  70. if (strlen(from) == 0)     /* Check for root dir */
  71.    {
  72.    from = "/";
  73.    }
  74.  
  75.   /* Check that dest dir exists before starting */
  76.  
  77. strcpy(newto,to);
  78. AddSlash(newto);
  79.  
  80. if (! MakeDirectoriesFor(newto))
  81.    {
  82.    sprintf(OUTPUT,"Unable to make directory for %s in copy: %s to %s\n",newto,ip->path,ip->destination);
  83.    CfLog(cferror,OUTPUT,"");
  84.    return;
  85.    }
  86.  
  87. if ((dirh = cfopendir(from,ip)) == NULL)
  88.    {
  89.    sprintf(OUTPUT,"copy can't open directory [%s]\n",from);
  90.    CfLog(cferror,OUTPUT,"");
  91.    return;
  92.    }
  93.  
  94. for (dirp = cfreaddir(dirh,ip); dirp != NULL; dirp = cfreaddir(dirh,ip))
  95.    {
  96.    if (!SensibleFile(dirp->d_name,from,ip))
  97.       {
  98.       continue;
  99.       }
  100.  
  101.    if (ip->purge == 'y') /* Do not purge this file */
  102.       {
  103.       AppendItem(&namecache,dirp->d_name,NULL);
  104.       }
  105.  
  106.    if (IgnoreFile(from,dirp->d_name,ip->ignores))
  107.       {
  108.       continue;
  109.       }
  110.  
  111.    strcpy(newfrom,from);                                   /* Assemble pathname */
  112.    AddSlash(newfrom);
  113.    strcpy(newto,to);
  114.    AddSlash(newto);
  115.  
  116.    if (BufferOverflow(newfrom,dirp->d_name))
  117.       {
  118.       printf(" culprit: RecursiveImage\n");
  119.       cfclosedir(dirh);
  120.       return;
  121.       }
  122.  
  123.    strcat(newfrom,dirp->d_name);
  124.  
  125.    if (BufferOverflow(newto,dirp->d_name))
  126.       {
  127.       printf(" culprit: RecursiveImage\n");
  128.       cfclosedir(dirh);
  129.       return;
  130.       }
  131.  
  132.    strcat(newto,dirp->d_name);
  133.  
  134.    if (TRAVLINKS || ip->linktype == 'n')
  135.       {
  136.       if (cfstat(newfrom,&statbuf,ip) == -1)
  137.          {
  138.          Verbose("%s: (Can't stat %s)\n",VPREFIX,newfrom);
  139.          continue;
  140.          }
  141.       }
  142.    else
  143.       {
  144.       if (cflstat(newfrom,&statbuf,ip) == -1)
  145.          {
  146.          Verbose("%s: (Can't stat %s)\n",VPREFIX,newfrom);
  147.          continue;
  148.          }
  149.       }
  150.  
  151.    if (!S_ISDIR(statbuf.st_mode) && IgnoredOrExcluded(image,dirp->d_name,ip->inclusions,ip->exclusions))
  152.       {
  153.       continue;
  154.       }
  155.    
  156.    if (S_ISDIR(statbuf.st_mode))
  157.       {    
  158.       bzero(&deststatbuf,sizeof(struct stat));
  159.       save_uid = (ip->uid)->uid;
  160.       save_gid = (ip->gid)->gid;
  161.       
  162.       if ((ip->uid)->uid == (uid_t)-1)          /* Preserve uid and gid  */
  163.      {
  164.      (ip->uid)->uid = statbuf.st_uid;
  165.      }
  166.       
  167.       if ((ip->gid)->gid == (gid_t)-1)
  168.      {
  169.      (ip->gid)->gid = statbuf.st_gid;
  170.      }
  171.  
  172.       if (stat(newto,&deststatbuf) == -1)
  173.      {
  174.      mkdir(newto,statbuf.st_mode);
  175.      }
  176.  
  177.       CheckCopiedFile(newto,ip->plus,ip->minus,fixall,ip->uid,ip->gid,&deststatbuf,&statbuf,NULL,ip->acl_aliases);
  178.  
  179.       (ip->uid)->uid = save_uid;
  180.       (ip->gid)->gid = save_gid;
  181.       
  182.       RecursiveImage(ip,newfrom,newto,maxrecurse-1);
  183.       }
  184.    else
  185.       {
  186.       CheckImage(newfrom,newto,ip);
  187.       }
  188.    }
  189.  
  190. if (ip->purge == 'y')
  191.    {
  192.    PurgeFiles(namecache,to);
  193.    DeleteItemList(namecache);
  194.    }
  195.  
  196. DeleteCompressedArray(ip->inode_cache);
  197.  
  198. ip->inode_cache = NULL;
  199.  
  200. cfclosedir(dirh);
  201. }
  202.  
  203. /*********************************************************************/
  204.  
  205. CheckHomeImages(ip)
  206.  
  207. struct Image *ip;
  208.  
  209. { CFDIR *dirh, *dirh2;
  210.   struct cfdirent *dirp, *dirp2;
  211.   char *ReadLastNode(), username[maxvarsize];
  212.   char homedir[bufsize],dest[bufsize];
  213.   struct passwd *pw;
  214.   struct stat statbuf;
  215.   struct Item *itp;
  216.   int request_uid = ip->uid->uid;  /* save if -1 */
  217.  
  218. if (!MountPathDefined())
  219.    {
  220.    printf("%s:  mountpattern is undefined\n",VPREFIX);
  221.    return;
  222.    }
  223.  
  224. if (cfstat(ip->path,&statbuf,ip))
  225.    {
  226.    sprintf(OUTPUT,"Master file %s doesn't exist for copying\n",ip->path);
  227.    CfLog(cferror,OUTPUT,"");
  228.    return;
  229.    }
  230.  
  231. for (itp = VMOUNTLIST; itp != NULL; itp=itp->next)
  232.    {
  233.    if (IsExcluded(itp->classes))
  234.       {
  235.       continue;
  236.       }
  237.    
  238.    if ((dirh = cfopendir(itp->name,ip)) == NULL)
  239.       {
  240.       sprintf(OUTPUT,"Can't open directory %s\n",itp->name);
  241.       CfLog(cferror,OUTPUT,"cfopendir");
  242.       return;
  243.       }
  244.  
  245.    for (dirp = cfreaddir(dirh,ip); dirp != NULL; dirp = cfreaddir(dirh,ip))
  246.       {
  247.       if (!SensibleFile(dirp->d_name,itp->name,ip))
  248.          {
  249.          continue;
  250.          }
  251.  
  252.       strcpy(homedir,itp->name);
  253.       AddSlash(homedir);
  254.       strcat(homedir,dirp->d_name);
  255.  
  256.       if (! IsHomeDir(homedir))
  257.          {
  258.          continue;
  259.          }
  260.  
  261.       if ((dirh2 = cfopendir(homedir,ip)) == NULL)
  262.          {
  263.      sprintf(OUTPUT,"Can't open directory %s\n",homedir);
  264.      CfLog(cferror,OUTPUT,"cfopendir");
  265.          return;
  266.          }
  267.  
  268.       for (dirp2 = cfreaddir(dirh2,ip); dirp2 != NULL; dirp2 = cfreaddir(dirh2,ip))
  269.          {
  270.          if (!SensibleFile(dirp2->d_name,homedir,ip))
  271.             {
  272.             continue;
  273.             }
  274.  
  275.          strcpy(username,dirp2->d_name);
  276.          strcpy(dest,homedir);
  277.          AddSlash(dest);
  278.          strcat(dest,dirp2->d_name);
  279.  
  280.          if (strlen(ip->destination) > 4)
  281.             {
  282.             AddSlash(dest);
  283.         if (strlen(ip->destination) < 6)
  284.            {
  285.            sprintf(OUTPUT,"Error in home/copy to %s",ip->destination);
  286.            CfLog(cferror,OUTPUT,"");
  287.            return;
  288.            }
  289.         else
  290.            {
  291.            strcat(dest,(ip->destination)+strlen("home/"));
  292.            }
  293.             }
  294.  
  295.          if (request_uid == -1)
  296.             {
  297.             if ((pw = getpwnam(username)) == NULL)
  298.                {
  299.                Debug2("cfengine: directory corresponds to no user %s - ignoring\n",username);
  300.                continue;
  301.                }
  302.             else
  303.                {
  304.                Debug2("(Setting user id to %s)\n",username);
  305.                }
  306.  
  307.             ip->uid->uid = pw->pw_uid;
  308.             }
  309.  
  310.          CheckImage(ip->path,dest,ip);
  311.          }
  312.       cfclosedir(dirh2);
  313.       }
  314.    cfclosedir(dirh);
  315.    }
  316. }
  317.  
  318. /*********************************************************************/
  319. /* Level 2                                                           */
  320. /*********************************************************************/
  321.  
  322. CheckImage(source,destination,ip)
  323.  
  324. char *source;
  325. char *destination;
  326. struct Image *ip;
  327.  
  328. { CFDIR *dirh;
  329.   char sourcefile[bufsize];
  330.   char sourcedir[bufsize];
  331.   char destdir[bufsize];
  332.   char destfile[bufsize];
  333.   struct stat sourcestatbuf, deststatbuf;
  334.   struct cfdirent *dirp;
  335.   int save_uid, save_gid, found;
  336.   
  337. Debug2("CheckImage (source=%s destination=%s)\n",source,destination);
  338.  
  339. if (ip->linktype == 'n')
  340.    {
  341.    found = cfstat(source,&sourcestatbuf,ip);
  342.    }
  343. else
  344.    {
  345.    found = cflstat(source,&sourcestatbuf,ip);
  346.    }
  347.  
  348. if (found == -1)
  349.    {
  350.    sprintf(OUTPUT,"Can't stat %s\n",source);
  351.    CfLog(cferror,OUTPUT,"");
  352.    FlushClientCache(ip);
  353.    return;
  354.    }
  355.  
  356. if (sourcestatbuf.st_nlink > 1)    /* Preserve hard link structure when copying */
  357.    {
  358.    RegisterHardLink(sourcestatbuf.st_ino,destination,ip);
  359.    }
  360.  
  361. save_uid = (ip->uid)->uid;
  362. save_gid = (ip->gid)->gid;
  363.  
  364. if ((ip->uid)->uid == (uid_t)-1)          /* Preserve uid and gid  */
  365.    {
  366.    (ip->uid)->uid = sourcestatbuf.st_uid;
  367.    }
  368.  
  369. if ((ip->gid)->gid == (gid_t)-1)
  370.    {
  371.    (ip->gid)->gid = sourcestatbuf.st_gid;
  372.    }
  373.  
  374. if (S_ISDIR(sourcestatbuf.st_mode))
  375.    {
  376.    strcpy(sourcedir,source);
  377.    AddSlash(sourcedir);
  378.    strcpy(destdir,destination);
  379.    AddSlash(destdir);
  380.  
  381.    if ((dirh = cfopendir(sourcedir,ip)) == NULL)
  382.       {
  383.       sprintf(OUTPUT,"%s: Can't open directory %s\n",VPREFIX,sourcedir);
  384.       CfLog(cferror,OUTPUT,"opendir");
  385.       FlushClientCache(ip);
  386.       (ip->uid)->uid = save_uid;
  387.       (ip->gid)->gid = save_gid;
  388.       return;
  389.       }
  390.  
  391.    /* Now check any overrides */
  392.  
  393.    CheckCopiedFile(destdir,ip->plus,ip->minus,fixall,ip->uid,ip->gid,&deststatbuf,&sourcestatbuf,NULL,ip->acl_aliases);
  394.    
  395.    for (dirp = cfreaddir(dirh,ip); dirp != NULL; dirp = cfreaddir(dirh,ip))
  396.       {
  397.       if (!SensibleFile(dirp->d_name,sourcedir,ip))
  398.          {
  399.          continue;
  400.          }
  401.  
  402.       strcpy(sourcefile, sourcedir);
  403.       
  404.       if (BufferOverflow(sourcefile,dirp->d_name))
  405.      {
  406.      FatalError("Culprit: CheckImage");
  407.      }
  408.   
  409.       strcat(sourcefile, dirp->d_name);
  410.       strcpy(destfile, destdir);
  411.       
  412.       if (BufferOverflow(destfile,dirp->d_name))
  413.      {
  414.      FatalError("Culprit: CheckImage");
  415.      }
  416.       
  417.       strcat(destfile, dirp->d_name);
  418.  
  419.       if (cflstat(sourcefile,&sourcestatbuf,ip) == -1)
  420.          {
  421.          printf("%s: Can't stat %s\n",VPREFIX,sourcefile);
  422.      FlushClientCache(ip);       
  423.      (ip->uid)->uid = save_uid;
  424.      (ip->gid)->gid = save_gid;
  425.          return;
  426.      }
  427.  
  428.       ImageCopy(sourcefile,destfile,sourcestatbuf,ip);
  429.       }
  430.  
  431.    cfclosedir(dirh);
  432.    FlushClientCache(ip);
  433.    (ip->uid)->uid = save_uid;
  434.    (ip->gid)->gid = save_gid;
  435.    return;
  436.    }
  437.  
  438. strcpy(sourcefile,source);
  439. strcpy(destfile,destination);
  440.  
  441. ImageCopy(sourcefile,destfile,sourcestatbuf,ip);
  442. (ip->uid)->uid = save_uid;
  443. (ip->gid)->gid = save_gid;
  444. FlushClientCache(ip);
  445. }
  446.  
  447. /*********************************************************************/
  448.  
  449. PurgeFiles(filelist,directory)
  450.  
  451. struct Item *filelist;
  452. char *directory;
  453.  
  454. { DIR *dirh;
  455.   struct stat statbuf; 
  456.   struct dirent *dirp;
  457.   char filename[bufsize];
  458.  
  459. Debug("PurgeFiles(%s)\n",directory);
  460.  
  461.  /* If we purge with no authentication we wipe out EVERYTHING */ 
  462.  
  463.  if (!AUTHENTICATED)
  464.     {
  465.     Verbose("Not purging %s - no verified contact with server\n",directory);
  466.     return;
  467.     }
  468.  
  469.  if ((dirh = opendir(directory)) == NULL)
  470.     {
  471.     sprintf(OUTPUT,"Can't open directory %s\n",directory);
  472.     CfLog(cferror,OUTPUT,"cfopendir");
  473.     return;
  474.     }
  475.  
  476.  for (dirp = readdir(dirh); dirp != NULL; dirp = readdir(dirh))
  477.     {
  478.     if (!SensibleFile(dirp->d_name,directory,NULL))
  479.        {
  480.        continue;
  481.        }
  482.  
  483.     if (! IsItemIn(filelist,dirp->d_name))
  484.        {
  485.        strcpy(filename,directory);
  486.        AddSlash(filename);
  487.        strcat(filename,dirp->d_name);
  488.        
  489.        if (DONTDO)
  490.       {
  491.       printf("%s: Need to purge %s from copy dest directory\n",filename);
  492.       }
  493.        else
  494.       {
  495.       sprintf(OUTPUT,"Purging %s in copy dest directory\n",filename);
  496.       CfLog(cfsilent,OUTPUT,"");
  497.       
  498.       if (unlink(filename) == -1)
  499.          {
  500.          if (stat(filename,&statbuf) == -1)
  501.         {
  502.         sprintf(OUTPUT,"Couldn't stat %s while purging\n",filename);
  503.         CfLog(cfverbose,OUTPUT,"stat");
  504.         }
  505.  
  506.          if (S_ISDIR(statbuf.st_mode))
  507.         {
  508.                 struct Tidy tp;
  509.         struct TidyPattern tpat;
  510.  
  511.         tp.recurse;
  512.         tp.tidylist = &tpat;
  513.         tp.next = NULL;
  514.         tp.path = filename;
  515.  
  516.         tpat.recurse = INFINITERECURSE;
  517.         tpat.age = 0;
  518.         tpat.size = 0;
  519.         tpat.pattern = strdup("*");
  520.         tpat.classes = strdup("any");;
  521.         tpat.defines = NULL;
  522.         tpat.dirlinks = 't';
  523.         tpat.rmdirs = 't';
  524.         tpat.searchtype = 'a';
  525.         tpat.log = 'd';
  526.         tpat.inform = 'd';
  527.         tpat.next = NULL;
  528.         RecursiveTidySpecialArea(filename,&tp,INFINITERECURSE);
  529.         free(tpat.pattern);
  530.         free(tpat.classes);
  531.         
  532.         if (rmdir(filename) == -1)
  533.            {
  534.            sprintf(OUTPUT,"Couldn't remove directory %s while purging\n",filename);
  535.            CfLog(cfverbose,OUTPUT,"rmdir");
  536.            }
  537.         continue;
  538.         }
  539.  
  540.          sprintf(OUTPUT,"Couldn't unlink %s while purging\n",filename);
  541.          CfLog(cfverbose,OUTPUT,"");
  542.          }
  543.       }
  544.        }
  545.     }
  546.  
  547.  closedir(dirh);
  548. }
  549.  
  550.  
  551. /*********************************************************************/
  552. /* Level 3                                                           */
  553. /*********************************************************************/
  554.  
  555. ImageCopy(sourcefile,destfile,sourcestatbuf,ip)
  556.  
  557. char *sourcefile;
  558. char *destfile;
  559. struct stat sourcestatbuf;
  560. struct Image *ip;
  561.  
  562. { char linkbuf[bufsize], *lastnode;
  563.   struct stat deststatbuf;
  564.   struct Link empty;
  565.   int succeed, i, silent = false, enforcelinks;
  566.   mode_t srcmode = sourcestatbuf.st_mode;
  567.   int ok_to_copy, found;
  568.   
  569. Debug2("ImageCopy(%s,%s,+%o,-%o)\n",sourcefile,destfile,ip->plus,ip->minus);
  570.  
  571. empty.defines = NULL;
  572.  
  573. if (IgnoredOrExcluded(image,sourcefile,ip->inclusions,ip->exclusions))
  574.    {
  575.    return;
  576.    }
  577.  
  578. if (ip->linktype != 'n')
  579.    {
  580.    if (IsWildItemIn(VLINKCOPIES,lastnode) || IsWildItemIn(ip->symlink,lastnode))
  581.       {
  582.       Verbose("cfengine: copy item %s marked for linking instead\n",sourcefile);
  583.       enforcelinks = ENFORCELINKS;
  584.       ENFORCELINKS = true;
  585.       
  586.       switch (ip->linktype)
  587.      {
  588.      case 's':
  589.          succeed = LinkFiles(destfile,sourcefile,NULL,NULL,NULL,true,&empty);
  590.          break;
  591.      case 'r':
  592.          succeed = RelativeLink(destfile,sourcefile,NULL,NULL,NULL,true,&empty);
  593.          break;
  594.      case 'a':
  595.          succeed = AbsoluteLink(destfile,sourcefile,NULL,NULL,NULL,true,&empty);
  596.          break;
  597.      default:
  598.          printf("%s: internal error, link type was [%c] in ImageCopy\n",VPREFIX,ip->linktype);
  599.          return;
  600.      }
  601.  
  602.       if (succeed)
  603.      {
  604.      ENFORCELINKS = enforcelinks;
  605.      lstat(destfile,&deststatbuf);
  606.      CheckCopiedFile(destfile,ip->plus,ip->minus,fixall,ip->uid,ip->gid,&deststatbuf,&sourcestatbuf,NULL,ip->acl_aliases);
  607.      }
  608.       
  609.       return;
  610.       }
  611.    }
  612.  
  613. if (strcmp(ip->action,"silent") == 0)
  614.    {
  615.    silent = true;
  616.    }
  617.  
  618. bzero(linkbuf,bufsize);
  619.  
  620. found = lstat(destfile,&deststatbuf);
  621.  
  622. if (found != -1)
  623.    {
  624.    if (S_ISLNK(deststatbuf.st_mode) && (ip->linktype == 'n'))
  625.       {
  626.       if (unlink(destfile) == -1)
  627.      {
  628.      sprintf(OUTPUT,"Couldn't remove link",destfile);
  629.      CfLog(cferror,OUTPUT,"unlink");
  630.      return;
  631.      }
  632.       Verbose("Removing old symbolic link %s to make way for copy\n",destfile);
  633.       found = -1;
  634.       }
  635.    }
  636.  
  637. if (found == -1)
  638.    {
  639.    if (strcmp(ip->action,"warn") == 0)
  640.       {
  641.       sprintf(OUTPUT,"Image file %s is non-existent\n",destfile);
  642.       CfLog(cfsilent,OUTPUT,"");
  643.       sprintf(OUTPUT,"(should be copy of %s)\n",sourcefile);
  644.       CfLog(cfsilent,OUTPUT,"");
  645.       return;
  646.       }
  647.  
  648.    if (S_ISREG(srcmode))
  649.       {
  650.       sprintf(OUTPUT,"%s wasn't at destination",destfile);
  651.       CfLog(cfverbose,OUTPUT,"");
  652.       sprintf(OUTPUT,"Copying from %s:%s\n",ip->server,sourcefile);
  653.       CfLog(cfinform,OUTPUT,"");
  654.  
  655.       if (CopyReg(sourcefile,destfile,sourcestatbuf,deststatbuf,ip))
  656.          {
  657.      stat(destfile,&deststatbuf);
  658.      CheckCopiedFile(destfile,ip->plus,ip->minus,fixall,ip->uid,ip->gid,&deststatbuf,&sourcestatbuf,NULL,ip->acl_aliases);
  659.      AddCopyClasses(ip);
  660.          }
  661.  
  662.       Debug2("Leaving ImageCopy\n");
  663.       return;
  664.       }
  665.  
  666.    if (S_ISFIFO (srcmode))
  667.       {
  668. #ifdef HAVE_MKFIFO
  669.       if (DONTDO)
  670.          {
  671.          Silent("%s: Make FIFO %s\n",VPREFIX,destfile);
  672.          }
  673.       else if (mkfifo (destfile,srcmode))
  674.          {
  675.          sprintf(OUTPUT,"Cannot create fifo `%s'", destfile);
  676.      CfLog(cferror,OUTPUT,"mkfifo");
  677.          return;
  678.          }
  679.       
  680.       AddCopyClasses(ip);
  681. #endif
  682.       }
  683.    else
  684.       {
  685.       if (S_ISBLK (srcmode) || S_ISCHR (srcmode) || S_ISSOCK (srcmode))
  686.          {
  687.          if (DONTDO)
  688.             {
  689.             Silent("%s: Make BLK/CHR/SOCK %s\n",VPREFIX,destfile);
  690.             }
  691.          else if (mknod (destfile, srcmode, sourcestatbuf.st_rdev))
  692.             {
  693.             sprintf(OUTPUT,"Cannot create special file `%s'",destfile);
  694.         CfLog(cferror,OUTPUT,"mknod");
  695.             return;
  696.             }
  697.      
  698.      AddCopyClasses(ip);
  699.          }
  700.       }
  701.  
  702.    if (S_ISLNK(srcmode))
  703.       {
  704.       if (cfreadlink(sourcefile,linkbuf,bufsize,ip) == -1)
  705.          {
  706.          sprintf(OUTPUT,"Can't readlink %s\n",sourcefile);
  707.      CfLog(cferror,OUTPUT,"");
  708.      Debug2("Leaving ImageCopy\n");
  709.          return;
  710.          }
  711.  
  712.       sprintf(OUTPUT,"Checking link from %s to %s\n",destfile,linkbuf);
  713.       CfLog(cfverbose,OUTPUT,"");
  714.  
  715.       if (ip->linktype == 'a' && linkbuf[0] != '/')      /* Not absolute path - must fix */
  716.          {
  717.          strcpy(VBUFF,sourcefile);
  718.          ChopLastNode(VBUFF);
  719.          AddSlash(VBUFF);
  720.          strcat(VBUFF,linkbuf);
  721.          strcpy(linkbuf,VBUFF);
  722.          }
  723.       
  724.       switch (ip->linktype)
  725.          {
  726.          case 's':
  727.                if (*linkbuf == '.')
  728.               {
  729.               succeed = RelativeLink(destfile,linkbuf,NULL,NULL,NULL,true,&empty);
  730.               }
  731.            else
  732.               {
  733.                       succeed = LinkFiles(destfile,linkbuf,NULL,NULL,NULL,true,&empty);
  734.               }
  735.                    break;
  736.          case 'r':
  737.                    succeed = RelativeLink(destfile,linkbuf,NULL,NULL,NULL,true,&empty);
  738.                break;
  739.          case 'a':
  740.                    succeed = AbsoluteLink(destfile,linkbuf,NULL,NULL,NULL,true,&empty);
  741.                    break;
  742.          default:
  743.                    printf("cfengine: internal error, link type was [%c] in ImageCopy\n",ip->linktype);
  744.                    return;
  745.      }
  746.  
  747.       if (succeed)
  748.      {
  749.      lstat(destfile,&deststatbuf);
  750.      CheckCopiedFile(destfile,ip->plus,ip->minus,fixall,ip->uid,ip->gid,&deststatbuf,&sourcestatbuf,NULL,ip->acl_aliases);
  751.      AddCopyClasses(ip);
  752.      }
  753.       }
  754.    }
  755. else
  756.    {
  757.    Debug("Destination file %s exists\n",destfile);
  758.    
  759.    if (! ip->force)
  760.       {
  761.       if (ip->size != cfnosize)
  762.          {
  763.          switch (ip->comp)
  764.               {
  765.                case '<':  if (sourcestatbuf.st_size > ip->size)
  766.                          {
  767.                         sprintf(OUTPUT,"Source file %s is > %d bytes in copy\n",sourcefile,ip->size);
  768.                  CfLog(cfsilent,OUTPUT,"");
  769.                      return;
  770.                          }
  771.                       break;
  772.             
  773.               case '=':  if (sourcestatbuf.st_size != ip->size)
  774.                          {
  775.                      sprintf(OUTPUT,"Source file %s is not %d bytes in copy\n",sourcefile,ip->size);
  776.                  CfLog(cfsilent,OUTPUT,"");
  777.                      return;
  778.                          }
  779.                       break;
  780.                
  781.            default:  if (sourcestatbuf.st_size < ip->size)
  782.                         {
  783.                     Silent(OUTPUT,"Source file %s is < %d bytes in copy\n",sourcefile,ip->size);
  784.                 CfLog(cfsilent,OUTPUT,"");
  785.                     return;
  786.                         }
  787.                       break;;
  788.            }
  789.          }
  790.  
  791.       switch (ip->type)
  792.          {
  793.          case 'c': if (S_ISREG(deststatbuf.st_mode) && S_ISREG(srcmode))
  794.               {
  795.                   ok_to_copy = CompareMD5CheckSums(sourcefile,destfile,ip,&sourcestatbuf,&deststatbuf);
  796.               }         
  797.                else
  798.                   {
  799.               Verbose("%s: Checksum comparison replaced by ctime: files not regular\n",VPREFIX);
  800.               Verbose("%s: %s -> %s\n",VPREFIX,sourcefile,destfile);
  801.               ok_to_copy = (deststatbuf.st_ctime < sourcestatbuf.st_ctime)||(deststatbuf.st_mtime < sourcestatbuf.st_mtime);
  802.                   }
  803.  
  804.                    if (ok_to_copy && strcmp(ip->action,"warn") == 0)
  805.                       { 
  806.                       Verbose("%s: Image file %s has a wrong MD5 checksum\n",VPREFIX,destfile);
  807.                       Verbose("%s: (should be copy of %s)\n",VPREFIX,sourcefile);
  808.                       return;
  809.                       }
  810.                break;
  811.  
  812.      case 'b': if (S_ISREG(deststatbuf.st_mode) && S_ISREG(srcmode))
  813.               {
  814.                   ok_to_copy = CompareBinarySums(sourcefile,destfile,ip,&sourcestatbuf,&deststatbuf);
  815.               }         
  816.                else
  817.                   {
  818.               Verbose("%s: Byte comparison replaced by ctime: files not regular\n",VPREFIX);
  819.               Verbose("%s: %s -> %s\n",VPREFIX,sourcefile,destfile);
  820.               ok_to_copy = (deststatbuf.st_ctime < sourcestatbuf.st_ctime)||(deststatbuf.st_mtime < sourcestatbuf.st_mtime);
  821.                   }
  822.  
  823.                    if (ok_to_copy && strcmp(ip->action,"warn") == 0)
  824.                       { 
  825.                       Verbose("%s: Image file %s has a wrong binary checksum\n",VPREFIX,destfile);
  826.                       Verbose("%s: (should be copy of %s)\n",VPREFIX,sourcefile);
  827.                       return;
  828.                       }
  829.                break;
  830.  
  831.      case 'm': ok_to_copy = (deststatbuf.st_mtime < sourcestatbuf.st_mtime);
  832.          
  833.                    if (ok_to_copy && strcmp(ip->action,"warn") == 0)
  834.                       { 
  835.                       Verbose("%s: Image file %s out of date\n",VPREFIX,destfile);
  836.                       Verbose("%s: (should be copy of %s)\n", VPREFIX,sourcefile);
  837.                       return;
  838.                       }
  839.                break;
  840.            
  841.          default:  ok_to_copy = (deststatbuf.st_ctime < sourcestatbuf.st_ctime)||(deststatbuf.st_mtime < sourcestatbuf.st_mtime);
  842.          
  843.                    if (ok_to_copy && strcmp(ip->action,"warn") == 0)
  844.                       { 
  845.                       Verbose("%s: Image file %s out of date\n",VPREFIX,destfile);
  846.                       Verbose("%s: (should be copy of %s)\n", VPREFIX,sourcefile);
  847.                       return;
  848.                       }
  849.                break;
  850.          }
  851.       }
  852.  
  853.  
  854.    if ((S_ISDIR(deststatbuf.st_mode)  && ! S_ISDIR(sourcestatbuf.st_mode))  ||
  855.        (S_ISREG(deststatbuf.st_mode)  && ! S_ISREG(sourcestatbuf.st_mode))  ||
  856.        (S_ISBLK(deststatbuf.st_mode)  && ! S_ISBLK(sourcestatbuf.st_mode))  ||
  857.        (S_ISCHR(deststatbuf.st_mode)  && ! S_ISCHR(sourcestatbuf.st_mode))  ||
  858.        (S_ISSOCK(deststatbuf.st_mode) && ! S_ISSOCK(sourcestatbuf.st_mode)) ||
  859.        (S_ISFIFO(deststatbuf.st_mode) && ! S_ISFIFO(sourcestatbuf.st_mode)) ||
  860.        (S_ISLNK(deststatbuf.st_mode)  && ! S_ISLNK(sourcestatbuf.st_mode)))
  861.        
  862.       {
  863.       printf("%s: image exists but destination type is silly (file/dir/link doesn't match)\n",VPREFIX);
  864.       printf("%s: source=%s, dest=%s\n",VPREFIX,sourcefile,destfile);
  865.       return;
  866.       }
  867.    
  868.    if ((ip->force) || ok_to_copy || S_ISLNK(sourcestatbuf.st_mode))  /* Always check links */
  869.       {
  870.       if (S_ISREG(srcmode))
  871.          {
  872.          sprintf(OUTPUT,"Updating image %s from master %s on %s\n",destfile,sourcefile,ip->server);
  873.      CfLog(cfinform,OUTPUT,"");
  874.  
  875.      AddCopyClasses(ip);
  876.  
  877.          if (CopyReg(sourcefile,destfile,sourcestatbuf,deststatbuf,ip))
  878.             {
  879.             stat(destfile,&deststatbuf);
  880.         CheckCopiedFile(destfile,ip->plus,ip->minus,fixall,ip->uid,ip->gid,&deststatbuf,&sourcestatbuf,NULL,ip->acl_aliases);
  881.             }
  882.  
  883.          return;
  884.          }
  885.  
  886.       if (S_ISLNK(sourcestatbuf.st_mode))
  887.          {
  888.          if (cfreadlink(sourcefile,linkbuf,bufsize,ip) == -1)
  889.             {
  890.             sprintf(OUTPUT,"Can't readlink %s\n",sourcefile);
  891.         CfLog(cferror,OUTPUT,"");
  892.             return;
  893.             }
  894.  
  895.          sprintf(OUTPUT,"Checking link from %s to %s\n",destfile,linkbuf);
  896.      CfLog(cfverbose,OUTPUT,"");
  897.  
  898.      enforcelinks = ENFORCELINKS;
  899.      ENFORCELINKS = true;
  900.  
  901.      switch (ip->linktype)
  902.         {
  903.         case 's':
  904.         if (*linkbuf == '.')
  905.            {
  906.            succeed = RelativeLink(destfile,linkbuf,NULL,NULL,NULL,true,&empty);
  907.            }
  908.         else
  909.            {
  910.            succeed = LinkFiles(destfile,linkbuf,NULL,NULL,NULL,true,&empty);
  911.            }
  912.         break;
  913.         case 'r':
  914.         succeed = RelativeLink(destfile,linkbuf,NULL,NULL,NULL,true,&empty);
  915.         break;
  916.         case 'a':
  917.         succeed = AbsoluteLink(destfile,linkbuf,NULL,NULL,NULL,true,&empty);
  918.         break;
  919.         default:
  920.         printf("cfengine: internal error, link type was [%c] in ImageCopy\n",ip->linktype);
  921.         return;
  922.         }
  923.  
  924.      if (succeed)
  925.         {
  926.         CheckCopiedFile(destfile,ip->plus,ip->minus,fixall,ip->uid,ip->gid,&deststatbuf,&sourcestatbuf,NULL,ip->acl_aliases);
  927.         }
  928.      ENFORCELINKS = enforcelinks;
  929.          }
  930.       }
  931.    else
  932.       {
  933.       CheckCopiedFile(destfile,ip->plus,ip->minus,fixall,ip->uid,ip->gid,&deststatbuf,&sourcestatbuf,NULL,ip->acl_aliases);
  934.  
  935.       Debug2("cfengine: image file is up to date: %s\n",destfile);
  936.       }
  937.    }
  938. }
  939.  
  940. /*********************************************************************/
  941.  
  942. cfstat(file,buf,ip)
  943.  
  944.  /* wrapper for network access */
  945.  
  946. char *file;
  947. struct stat *buf;
  948. struct Image *ip;
  949.  
  950. { int res;
  951.  
  952. if (ip == NULL)
  953.    {
  954.    res = stat(file,buf);
  955.    /* CheckForHoles(buf,ip); Don't need this if ip is NULL */
  956.    return res;
  957.    }
  958.  
  959. if (strcmp(ip->server,"localhost") == 0)
  960.    {
  961.    res = stat(file,buf);
  962.    CheckForHoles(buf,ip);
  963.    return res;
  964.    }
  965. else
  966.    {
  967.    return cf_rstat(file,buf,ip,"file");
  968.    }
  969. }
  970.  
  971. /*********************************************************************/
  972.  
  973. cflstat(file,buf,ip)
  974.  
  975. char *file;
  976. struct stat *buf;
  977. struct Image *ip;
  978.  
  979.  /* wrapper for network access */
  980.  
  981. { int res;
  982.  
  983. if (ip == NULL)
  984.    {
  985.    res = lstat(file,buf);
  986.    /* CheckForHoles(buf,ip); Don't need this if ip is NULL */
  987.    return res;
  988.    }
  989.  
  990. if (strcmp(ip->server,"localhost") == 0)
  991.    {
  992.    res = lstat(file,buf);
  993.    CheckForHoles(buf,ip);
  994.    return res;
  995.    }
  996. else
  997.    {
  998.    /* read cache if possible */
  999.    return cf_rstat(file,buf,ip,"link");
  1000.    }
  1001. }
  1002.  
  1003. /*********************************************************************/
  1004.  
  1005. cfreadlink(sourcefile,linkbuf,buffsize,ip)
  1006.  
  1007. char *sourcefile, *linkbuf;
  1008. int buffsize;
  1009. struct Image *ip;
  1010.  
  1011.  /* wrapper for network access */
  1012.  
  1013. { struct cfstat *sp;
  1014.  
  1015. if (strcmp(ip->server,"localhost") == 0)
  1016.    {
  1017.    return readlink(sourcefile,linkbuf,buffsize);
  1018.    }
  1019.  
  1020. for (sp = ip->cache; sp != NULL; sp=sp->next)
  1021.    {
  1022.    if ((strcmp(ip->server,sp->cf_server) == 0) && (strcmp(sourcefile,sp->cf_filename) == 0))
  1023.       {
  1024.       if (sp->cf_readlink != NULL)
  1025.      {
  1026.      if (strlen(sp->cf_readlink)+1 > buffsize)
  1027.         {
  1028.         printf("%s: readlink value is too large in cfreadlink\n",VPREFIX);
  1029.         printf("%s: [%s]]n",VPREFIX,sp->cf_readlink);
  1030.         return -1;
  1031.         }
  1032.      else
  1033.         {
  1034.         bzero(linkbuf,buffsize);
  1035.         strcpy(linkbuf,sp->cf_readlink);
  1036.         return 0;
  1037.         }
  1038.      }
  1039.       }
  1040.    }
  1041.  
  1042. return -1;
  1043. }
  1044.  
  1045. /*********************************************************************/
  1046.  
  1047. CFDIR *cfopendir(name,ip)
  1048.  
  1049. char *name;
  1050. struct Image *ip;
  1051.  
  1052. { CFDIR *cf_ropendir(),*returnval;
  1053.  
  1054. if (strcmp(ip->server,"localhost") == 0)
  1055.    {
  1056.    if ((returnval = (CFDIR *)malloc(sizeof(CFDIR))) == NULL)
  1057.       {
  1058.       FatalError("Can't allocate memory in cfopendir()\n");
  1059.       }
  1060.    
  1061.    returnval->cf_list = NULL;
  1062.    returnval->cf_listpos = NULL;
  1063.    returnval->cf_dirh = opendir(name);
  1064.  
  1065.    if (returnval->cf_dirh != NULL)
  1066.       {
  1067.       return returnval;
  1068.       }
  1069.    else
  1070.       {
  1071.       free ((char *)returnval);
  1072.       return NULL;
  1073.       }
  1074.    }
  1075. else
  1076.    {
  1077.    return cf_ropendir(name,ip);
  1078.    }
  1079. }
  1080.  
  1081. /*********************************************************************/
  1082.  
  1083. struct cfdirent *cfreaddir(cfdirh,ip)
  1084.  
  1085. CFDIR *cfdirh;
  1086. struct Image *ip;
  1087.  
  1088.   /* We need this cfdirent type to handle the weird hack */
  1089.   /* used in SVR4/solaris dirent structures              */
  1090.  
  1091. { static struct cfdirent dir;
  1092.   struct dirent *dirp;
  1093.  
  1094. bzero(dir.d_name,bufsize);
  1095.  
  1096. if (strcmp(ip->server,"localhost") == 0)
  1097.    {
  1098.    dirp = readdir(cfdirh->cf_dirh);
  1099.  
  1100.    if (dirp == NULL)
  1101.       {
  1102.       return NULL;
  1103.       }
  1104.    strncpy(dir.d_name,dirp->d_name,bufsize);
  1105.    return &dir;
  1106.    }
  1107. else
  1108.    {
  1109.    if (cfdirh->cf_listpos != NULL)
  1110.       {
  1111.       strncpy(dir.d_name,(cfdirh->cf_listpos)->name,bufsize);
  1112.       cfdirh->cf_listpos = cfdirh->cf_listpos->next;
  1113.       return &dir;
  1114.       }
  1115.    else
  1116.       {
  1117.       return NULL;
  1118.       }
  1119.    }
  1120. }
  1121.  
  1122. /*********************************************************************/
  1123.  
  1124. cfclosedir(dirh)
  1125.  
  1126. CFDIR *dirh;
  1127.  
  1128. {
  1129. if ((dirh != NULL) && (dirh->cf_dirh != NULL))
  1130.    {
  1131.    closedir(dirh->cf_dirh);
  1132.    }
  1133.  
  1134. Debug("cfclosedir()\n");
  1135. DeleteItemList(dirh->cf_list);
  1136. free((char *)dirh); 
  1137. }
  1138.  
  1139. /*********************************************************************/
  1140. /* Level 2                                                           */
  1141. /*********************************************************************/
  1142.  
  1143. CopyReg (source,dest,sstat,dstat,ip)
  1144.  
  1145. char *source, *dest;
  1146. struct stat sstat, dstat;
  1147. struct Image *ip;
  1148.  
  1149. { char backup[bufsize];
  1150.   char new[bufsize], *linkable;
  1151.   int remote = false, silent;
  1152. #ifdef HAVE_UTIME_H
  1153.   struct utimbuf timebuf;
  1154. #endif  
  1155.  
  1156. Debug2("CopyReg(%s,%s)\n",source,dest);
  1157.  
  1158. if (DONTDO)
  1159.    {
  1160.    printf("%s: copy from %s to %s\n",VPREFIX,source,dest);
  1161.    return false;
  1162.    }
  1163.  
  1164.  /* Make an assoc array of inodes used to preserve hard links */
  1165.  
  1166. linkable = CompressedArrayValue(ip->inode_cache,sstat.st_ino);
  1167.  
  1168. if (sstat.st_nlink > 1)  /* Preserve hard links, if possible */
  1169.    {
  1170.    if (CompressedArrayElementExists(ip->inode_cache,sstat.st_ino) && (strcmp(dest,linkable) != 0))
  1171.       {
  1172.       unlink(dest);
  1173.  
  1174.       silent = SILENT;
  1175.       SILENT = true;
  1176.       
  1177.       DoHardLink(dest,linkable,NULL);
  1178.       
  1179.       SILENT = silent;
  1180.       return true;
  1181.       }
  1182.    }
  1183.  
  1184. if (strcmp(ip->server,"localhost") != 0)
  1185.    {
  1186.    Debug("This is a remote copy from server: %s\n",ip->server);
  1187.    remote = true;
  1188.    }
  1189.  
  1190. strcpy(new,dest);
  1191. strcat(new,CF_NEW);
  1192.  
  1193. if (remote)
  1194.    {
  1195.    if (!CopyRegNet(source,new,ip,sstat.st_size))
  1196.       {
  1197.       return false;
  1198.       }
  1199.    }
  1200. else
  1201.    {
  1202.    if (!CopyRegDisk(source,new,ip))
  1203.       {
  1204.       return false;
  1205.       }
  1206.  
  1207.    if (ip->stealth == 't')
  1208.       {
  1209. #ifdef HAVE_UTIME_H
  1210.       timebuf.actime = sstat.st_atime;
  1211.       timebuf.modtime = sstat.st_mtime;
  1212.       utime(source,&timebuf);
  1213. #endif      
  1214.       }
  1215.    }
  1216.  
  1217. Debug("CopyReg succeeded in copying to %s to %s\n",source,new);
  1218.  
  1219. if (IMAGEBACKUP)
  1220.    {
  1221.    strcpy(backup,dest);
  1222.    strcat(backup,CF_SAVED);
  1223.  
  1224.    if (IsItemIn(VREPOSLIST,backup))
  1225.       {
  1226.       return true;
  1227.       }
  1228.  
  1229.    if (rename(dest,backup) == -1)
  1230.       {
  1231.       /* ignore */
  1232.       }
  1233.    }
  1234.  
  1235. stat(new,&dstat);
  1236.  
  1237. if (dstat.st_size != sstat.st_size)
  1238.    {
  1239.    sprintf(OUTPUT,"WARNING: new file %s seems to have been corrupted in transit, aborting!\n",new);
  1240.    CfLog(cfverbose,OUTPUT,"");
  1241.    if (rename(backup,dest) == -1)
  1242.       {
  1243.       /* ignore */
  1244.       }
  1245.    return false;
  1246.    }
  1247.  
  1248. if (ip->secure)
  1249.    {
  1250.    Debug("Final verification of transmission...\n");
  1251.    if (CompareMD5CheckSums(source,new,ip,&sstat,&dstat))
  1252.       {
  1253.       sprintf(OUTPUT,"WARNING: new file %s seems to have been corrupted in transit, aborting!\n",new);
  1254.       CfLog(cfverbose,OUTPUT,"");
  1255.       if (rename(backup,dest) == -1)
  1256.      {
  1257.      /* ignore */
  1258.      }
  1259.       return false;
  1260.       }
  1261.    }
  1262.  
  1263. if (rename(new,dest) == -1)
  1264.    {
  1265.    sprintf(OUTPUT,"Problem: could not install copy file as %s, directory in the way?\n",dest);
  1266.    CfLog(cferror,OUTPUT,"rename");
  1267.    rename(backup,dest);
  1268.    return false;
  1269.    }
  1270.  
  1271. if (IMAGEBACKUP && Repository(backup))
  1272.    {
  1273.    unlink(backup);
  1274.    }
  1275.  
  1276. return true;
  1277. }
  1278.  
  1279.  
  1280. /*********************************************************************/
  1281.  
  1282. AddCopyClasses(ip)
  1283.  
  1284. struct Image *ip;
  1285.  
  1286. { char *sp;
  1287.   char currentitem[maxvarsize];
  1288.  
  1289. Debug("Entering AddCopyClasses(%s)\n",ip->defines);
  1290.  
  1291. for (sp = ip->defines; *sp != '\0'; sp++)
  1292.    {
  1293.    currentitem[0] = '\0';
  1294.  
  1295.    sscanf(sp,"%[^,:.]",currentitem);
  1296.  
  1297.    sp += strlen(currentitem)-1;
  1298.  
  1299.    AddClassToHeap(currentitem);
  1300.    }
  1301. }
  1302.  
  1303. /*********************************************************************/
  1304. /* Level 3                                                           */
  1305. /*********************************************************************/
  1306.  
  1307. RegisterHardLink(i,value,ip)
  1308.  
  1309. int i;
  1310. char *value;
  1311. struct Image *ip;
  1312.  
  1313. {
  1314. if (!FixCompressedArrayValue(i,value,&(ip->inode_cache)))
  1315.    {
  1316.     /* Not root hard link, remove to preserve consistency */
  1317.    Verbose("Removing old hard link %s to preserve structure..\n",value);
  1318.    unlink(value);
  1319.    }
  1320. }
  1321.